package GuiController;

import com.jme3.app.SimpleApplication;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import danceDoll.AnimationControl;
import danceDoll.BVHController;
import danceDoll.DanceDoll;
import danceDoll.Initialize;
import danceDoll.Record;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.NiftyEventSubscriber;
import de.lessvoid.nifty.controls.Slider;
import de.lessvoid.nifty.controls.SliderChangedEvent;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.render.ImageRenderer;
import de.lessvoid.nifty.elements.render.TextRenderer;
import de.lessvoid.nifty.layout.align.HorizontalAlign;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Controlls all gui buttons and sliders. Handles the save and load dialog windows-
 * @author Christian Braun
 * @version v2.0 final
 */
public final class GuiController implements ScreenController {
 
  private Nifty nifty;
  private SimpleApplication app;
  private Camera cam;
  private Vector3f home,home2;
  private AnimationControl ani;
  private Element errorPopup;
  private Vector3f lastViewPos;
  private Vector3f lastView;
  private String url1,url2,url3,url4,url5;
  private Slider sliderHeight, sliderZoom, sliderTurn, sliderTilt;
  private boolean chkRec= true;
  private boolean popup;   //popup open
  private boolean blinkStat = true; //rec-button status
  private Initialize init;
  private boolean music = true;
  private Record record;
  private FileLoader fileloader = new FileLoader();
  
 
  
 /**
   * GuiController Constructor
   * 
   * @param nifty Nifty
   * @param dd DanceDoll
   * @param init Initialize
   */
  public GuiController(Nifty nifty, DanceDoll dd, Initialize init) { 
    this.app = dd;
    this.nifty = nifty;
    this.cam = dd.getCamera();
    this.init = init;
    this.home = new Vector3f(0.0f,10.0f,19.49f);
    this.home2 = new Vector3f(0.0f,5.0f,0.0f);
    this.ani = init.getAnimationControl();
    this.lastViewPos = cam.getLocation();
    this.lastView = new Vector3f(0.f,5.f,0.f);
    this.record = init.getRecord();
    // Standard Animationen aus Assets
    url1 = "Animations/06_linkes_Bein nach_vorn_usw.bvh";
    url2 = "Animations/07_Ellbow_to_knee.bvh";
    url3 = "Animations/17_SPECIAL_taucher.bvh";
    url4 = "Animations/15_Arme_hoch_klatschen.bvh";
    url5 = "Animations/16_Fail.bvh";
            
    home();
  }
    
  /** 
   * Bind nifty
   * 
   * @param nifty
   * @param screen 
   */
 
  public void bind(Nifty nifty, Screen screen) {
    this.nifty = nifty;
  }
 
  public void onStartScreen() { }
 
  // Controlls on left side
  
  /**
   * Plays the BVH-file from choosen button
   * @param id Button-ID (String) in gui.xml
   */
  
  public void play(String id) {
      
      int chk = Integer.parseInt(id);
      String URL = "";
      switch (chk) {
          case 1 : URL = this.url1;break;
          case 2 : URL = this.url2;break;
          case 3 : URL = this.url3;break;
          case 4 : URL = this.url4;break;
          case 5 : URL = this.url5;break;
      }
      
      if (URL.substring(0,1).equals("A")){ // Abfrage, ob aus Systemordner oder aus Assets geladen wird
        try {
            BVHController bvh = new BVHController(URL);
            if (bvh.chkBVH()) {
                ani.startAnimation(bvh);
            }
        } catch (IOException ex) {
            Logger.getLogger(GuiController.class.getName()).log(Level.SEVERE, null, ex);
        }
       }
      else{
          File file = new File(URL);
          try {
            BVHController bvh = new BVHController(file);
            if (bvh.chkBVH()) {
                ani.startAnimation(bvh);
            }
        } catch (IOException ex) {
            Logger.getLogger(GuiController.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
  }
 
/**
   * Loads BVH-file to selected button
   * @param id Load-button-id (String) in gui.xml
   * @throws IOException 
   */
  
  public void load(String id) throws IOException{
      fileloader.openDialog("load"); 
      int chk = Integer.parseInt(id);
     
      switch (chk) { // String id zuweisen und Text in Gui ändern
          case 1 : url1 = fileloader.getFile().getAbsolutePath();break;
          case 2 : url2 = fileloader.getFile().getAbsolutePath();break;
          case 3 : url3 = fileloader.getFile().getAbsolutePath();break;
          case 4 : url4 = fileloader.getFile().getAbsolutePath();break;
          case 5 : url5 = fileloader.getFile().getAbsolutePath();break;
      }
        
       try {
            BVHController bvh = new BVHController(fileloader.getFile());
            if (bvh.chkBVH()) {
                ani.startAnimation(bvh);
                changeText("File_text_" + id,fileloader.toString());
            }
        } catch (IOException ex) {
            Logger.getLogger(GuiController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
  
  
  
  // Controlls on right side
  
  /**
   * Sets the camera position and lookAtDirection to the home position of the camera
   */
  
  public void home(){
      if(sliderHeight != null){
          sliderHeight.setValue(50.f);
      }
      if(sliderZoom != null){
          sliderZoom.setValue(50.f);
      }
      if(sliderTilt != null){
          sliderTilt.setValue(50.f);
      }
      if(sliderTurn != null){
          sliderTurn.setValue(0.f);
      }
      
      cam.setLocation(home);
      cam.lookAt(home2, Vector3f.UNIT_Y);
      lastView = new Vector3f(0.f,5.f,0.f);
      lastViewPos = new Vector3f(cam.getLocation());  
      init.turntable = true;  
  }
  
  /**
   * Mutes the music and switches lights off
   */
  
  public void musicOnOff(){
   if (init.music) {
        init.getStuMusic().pause();
        init.music =false;
        BVHController bvh;
          try {
            bvh = new BVHController("Animations/01_Kopf_Kratzen_uhr_schauen.bvh");
                if (bvh.chkBVH()) {
                ani.startAnimation(bvh);
                 }
          } 
          catch (IOException ex) {
               Logger.getLogger(Initialize.class.getName()).log(Level.SEVERE, null, ex);
               }
    } 
    else {
       init.getStuMusic().play();
       init.music =true;
    }                 
  }
  
  /**
   * Changes the music volume
   * @param id Slider ID in gui.xml
   * @param event SliderChangedEvent
   */
   
  @NiftyEventSubscriber(id="volume")
  public void volume(final String id, final SliderChangedEvent event){
  init.getStuMusic().setVolume(event.getValue()/100.f);
  }
  
  
  /**
   * Plays the recorded file. if no file is recorded and saved a error-pop-up open
   */
  public void recPlay(){
      if (record.getURL() != null){
          File file = new File(record.getURL());
          try {
            BVHController bvh = new BVHController(file);
            if (bvh.chkBVH()) {
                ani.startAnimation(bvh);
            }
        } catch (IOException ex) {
            Logger.getLogger(GuiController.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
      else{
          startErrorPopup("Es wurden noch keine Bewegungen aufgezeichnet.\nDrücken Sie den REC Button um eine Aufnahme zu starten.");
      }  
  }
  
  /**
   * Updates the time and frame number in the text field next to the record button
   */
  public void updateFrames() {
      float tmp = record.getCurrentFrame()*record.getFrameTime();
      
      int min =(int) Math.floor(tmp/60);
      int sec = (int)Math.floor(tmp-(min*60));
      int frames = (int) ((tmp-sec-min*60)*100/4.167);
      String minString = String.valueOf(min);
      String secString = String.valueOf(sec);
      String framesString = String.valueOf(frames);
      if(sec <=9)
          secString = "0"+secString;
      if(frames <=9)
          framesString = "0"+framesString;
      if(min <= 9)
          minString = "0"+minString;
      changeText("TimeCount", minString+":"+secString+":"+framesString);
      changeText("FrameCount","Frame: " + record.getCurrentFrame());
  }
  
  /**
   * Starts a record sequence
   */
  
  public void rec() throws IOException {
      if (chkRec != true){ // Check, ob Rec_Botton 1 oder 2 mal gedrückt wurde
          chkRec = true;
          recStop();
      }
      else {
           chkRec = false;
           
           record = this.init.getRecord();
           record.startRec(); // Wenn 2. mal gedrückt --> speichern
      }
  }
  
  /**
   *  Stops a record sequence, opens a FileLoader dialog window
   */
  public void recStop() throws IOException{
      record.stopRec();
      fileloader.openDialog("save");
      if(fileloader.getFile().getAbsolutePath().substring(fileloader.getFile().getAbsolutePath().length()-4, fileloader.getFile().getAbsolutePath().length()).equals(".bvh"))
        record.setURL(fileloader.getFile().getAbsolutePath());
      else
          record.setURL(fileloader.getFile().getAbsolutePath()+".bvh");
      record.save(); 
      changeText("rec_play_text", fileloader.getFile().getName());
  }
  
  
  /* 
   * Changes the distance of the camera to the character
   * 
   * @param id Slider-ID
   * @param event SliderChangedEvent
   */
  
  @NiftyEventSubscriber(id="zoom")
  
  public void zoom(final String id, final SliderChangedEvent event) { 
      sliderZoom = event.getSlider();
      cam.setLocation(new Vector3f(0.f, lastViewPos.y,8.f+(event.getValue()/4.35f)));
      cam.lookAt(lastView, Vector3f.UNIT_Y); 
  }
  
  /**
   * Changes the height of the camera
   * 
   * @param id Slider Id in gui.xml
   * @param event SliderChangedEvent
   * 
   * change the hight of the camera in y-direction
   */
    @NiftyEventSubscriber(id="height")
    public void hight(final String id, SliderChangedEvent event) {
      sliderHeight = event.getSlider();
      cam.setLocation(new Vector3f(cam.getLocation().x,5.f+event.getValue()/10.f,cam.getLocation().z));
      cam.lookAt(lastView,Vector3f.UNIT_Y);
      lastViewPos = new Vector3f(cam.getLocation());
  }
 
  /**
     * Changes the viewing direction of the camera
     * 
     * @param slider-id
     * @param SliderChangedEvent
     * change the tilt of the camera
     */
  @NiftyEventSubscriber(id="tilt") // TODO kleiner Scale Bug... sonst scale rauswerfen!
  public void tilt(final String id, final SliderChangedEvent event) {
  sliderTilt = event.getSlider();
  float scale;
  if (sliderZoom != null){
      scale = sliderZoom.getValue()/100.f;
  }
  else scale = 0.5f;  
  cam.lookAt(new Vector3f (lastView.x,((event.getValue()/10.f)*(1.3f-scale)),lastView.z),Vector3f.UNIT_Y);
  lastView = new Vector3f (lastView.x,((event.getValue()/10.f)*(1.3f-scale)),lastView.z);
  }  
  
 /**
   * Rotates the dancefloor in a range from 0-90°.
   * if 0° is choosen dancefloor starts to turn on its on.
   * @param id Slider-Id in gui.xml
   * @param event SliderChangedEvent
   */
  
  @NiftyEventSubscriber(id="turn") // TODO VALUE to Angle an VINCE!!!
  public void turn(final String id, final SliderChangedEvent event) {
      sliderTurn = event.getSlider();
      if (sliderTurn.getValue() == 0.f){
          init.turntable = true;
      }
      else{
          init.turntable = false;
          init.getRoot().getChild("turntable").setLocalRotation(new Quaternion(new float[]{0, (sliderTurn.getValue()*3.3f * FastMath.DEG_TO_RAD), 0}));
      }
  }
  
  public void onEndScreen() { }
 
  /** jME3 AppState methods */ 
  /**
   * quit game
   */
  public void quitGame() {
    app.stop(); 
  }
  
  /**
   * Changes to another nifty screen
   * @param nextScreen 
   */
  public void changeScreen(String nextScreen){
    nifty.gotoScreen(nextScreen);
    if(nextScreen.equals("run"))
        startMusic();
  }
  
  /**
  * Starts the music
  */
  public void startMusic(){
    init.initMusic();
  }
  
  /**
  * Opens a popup window with a message
  * @param message message
  */
  public void startErrorPopup(String message){
    String errorMessage = message;
    if (errorMessage == null){errorMessage = "empty message";}
    if (popup){
        Element textElement = errorPopup.findElementByName("errorMessage");
        TextRenderer textRenderer = textElement.getRenderer(TextRenderer.class);
        String addMessage = (textRenderer.getOriginalText() + "\n" + errorMessage);
        errorMessage = addMessage;
        closePopup();
    }
    errorPopup = nifty.createPopup("errorPopup");
    Element textElement = errorPopup.findElementByName("errorMessage");
    TextRenderer textRenderer = textElement.getRenderer(TextRenderer.class);
    textRenderer.setText(errorMessage);
    nifty.showPopup(nifty.getCurrentScreen(), errorPopup.getId(), null);
    popup = true;
  }

  /**
  * Close an open popup window
  */
  public void closePopup(){
    nifty.closePopup(errorPopup.getId());
    popup = false;
  }
  
  /**
   * Changes a text element
   * @param id of the text element, 
   * @param newText new text
   */
  public void changeText(String id, String newText){
    // cut text
    if (newText.length() > 17){
        newText = newText.substring(0, 17);
    }
    newText = ("  " + newText);
    // find the element
    Element textElement = nifty.getCurrentScreen().findElementByName(id);
    // get the TextRenderer
    TextRenderer textRenderer = textElement.getRenderer(TextRenderer.class);
    // change the text
    textRenderer.setText(newText);
    textRenderer.setTextHAlign(HorizontalAlign.left);
  }
   
  /**
  * rec button image switches
  */
  public void recBlink(){ 
    if (blinkStat){
        changePicOnce("rec", "Interface/Button/Rec_pressed.png");
        blinkStat = false;
    }
    else{
        changePicOnce("rec", "Interface/Button/Rec_select.png");
        blinkStat = true;
    } 
  }
   
  /**
  * Changes a picture
  * @param imageId id of the image, 
  * @param newImage new image file path
  */
  public void changePicOnce(String imageId, String newImage){
    Element imageElement = nifty.getCurrentScreen().findElementByName(imageId);
    ImageRenderer imageRenderer = imageElement.getRenderer(ImageRenderer.class);
    imageRenderer.setImage(nifty.getRenderEngine().createImage(newImage,false));
  }
  

}
